#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <sys/select.h>
#include <errno.h>
#include "Socket.hpp"
#include "Logger.hpp"
#include "InetAddr.hpp"
#include <unistd.h>



class SelectServer
{
    inline static const int default_size = sizeof(fd_set) * 8;//理论上select可以检测1024个(位图结构中的fd):0~1023
    inline static const int default_fd = 0;//默认标为0，表示不存在
public:
    SelectServer(uint16_t port = 8080):_listensock(std::make_unique<TcpSocket>()),_helper_arr(default_size,default_fd)
    {
        //RAII风格
        _listensock->BuildListenSocketMethod(port);
        
        _helper_arr[_listensock->SockFd()] = 1;
    }


    void Accept()
    {
        InetAddr client;
        socklen_t len = client.Len();
        int fd = accept(_listensock->SockFd(),(struct sockaddr*)&client.Addr(),&len);
        if(fd < 0)
            LOG(LogLevel::ERROR) << "accept error";
        else
        {
            LOG(LogLevel::INFO) << "accept success";
            _helper_arr[fd] = 1;//添加到辅助数组中
        }
    }
    
    void Recv(int fd)
    {
        int buffer[1024] = {0};
        int n = recv(fd,buffer,sizeof(buffer) - 1,0);//等待不再由recv完成
        if(n > 0)
        {
            LOG(LogLevel::INFO) << "recv success";
            buffer[n] = 0;
            send(fd,buffer,n,0);
        }
        else if(n == 0)
        {
            LOG(LogLevel::INFO) << "client quit";
            _helper_arr[fd] = 0;
            close(fd);
        }
        else
        {
            LOG(LogLevel::ERROR) << "recv error";
        }
    }
    void EventDispatch(fd_set* rfds)
    {
        for(int i = 0;i < default_size;i++)
        {
            if(_helper_arr[i] == 0)
                continue;
            if(FD_ISSET(i,rfds))
            {
                if(i == _listensock->SockFd())
                    Accept();
                else
                    Recv(i);
            }
        }
    }
    void Run()
    {
        fd_set rfds;
        int max_fd;
        struct timeval t = {5,0};
        while(true)
        {
            max_fd = -1;
            FD_ZERO(&rfds);
            //通过辅助数组，将要检测的fd重置
            for(int i = 0;i < default_size;i++)
            {
                if(_helper_arr[i] == 0)
                    continue;
                FD_SET(i,&rfds);
                max_fd = std::max(max_fd,i);
            }

            //明确要检测的fd后,进行select等待
            int n = select(max_fd + 1,&rfds,nullptr,nullptr,nullptr);//最后一个参数如果传入timeval结构，则为非阻塞(阻塞特定时间)；传入nullptr,则表示阻塞式等待
            if(n > 0)
            {
                LOG(LogLevel::INFO) << "select success";
                //进行任务派发
                EventDispatch(&rfds);
            }
            else if(n == 0)
            {
                LOG(LogLevel::INFO) << "select timeout";
                continue;
            }
            else 
            {
                //如果被信号中断了，那么重来一次
                if(errno == EINTR)
                    continue;                
                else
                {
                    LOG(LogLevel::ERROR) << "select error";
                    exit(errno); 
                }
            }
        }
    }

    

    ~SelectServer()
    {}
private:
    std::unique_ptr<Socket> _listensock;
    std::vector<int> _helper_arr;
};
